/*
 * Copyright © 2008 PCCW Solutions All right reserved.
 *
 */
package com.blues.framework.db;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.commons.dbutils.DbUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.sina.sae.util.SaeUserInfo;

/**
 * 数据库操作会话类
 * 
 * @author: Kyle.Zhang 2009-1-12 18:11:51
 */
public class Session {
	private static final Logger logger = Logger.getLogger(Session.class);

	/**
	 * 事务时使用的数据库连接对象
	 */
	private Connection dbConn;

	/**
	 * JDBC数据库连接信息
	 */
	private static String jdbcDriver = "com.mysql.jdbc.Driver"; // JDBC驱动

	private static String jdbcUrl = "jdbc:mysql://w.rdc.sae.sina.com.cn:3307/app_eyun"; // 数据库连接串

	private static String jdbcUser = SaeUserInfo.getAccessKey(); // 数据库用户名

	private static String jdbcPass = SaeUserInfo.getSecretKey(); // 数据库用户密码

	/**
	 * 数据源对象
	 */
	private static DataSource ds;
	static {
			try {
				Class.forName(jdbcDriver);
			} catch (Exception exp) {
				logger.error(exp.getMessage(), exp);
			}
	}

	/**
	 * 是否起用事务
	 */
	private boolean transactionStarted = false;

	/**
	 * 查询事务是否启动
	 */
	public boolean isTransactionStarted() {
		return transactionStarted;
	}

	/**
	 * 获取当前数据库连接对象，如果没有则从DataSource中取一个
	 * 
	 * @throws SQLException
	 */
	public Connection getConnection() throws SQLException {
		logger.debug(">>>getConnection()");

		if (dbConn == null) {
			try {
				dbConn = newConnection();

				// dbConn = confirmOpen(dbConn);
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
				// throw e;
			}
			// } else {
			// dbConn = confirmOpen(dbConn);
		}

		logger.debug("<<<getConnection()");
		return dbConn;
	}

	// // UPD Start EHR- by Zane.Wang 2010-4-29
	// // 江西报以下错误 java.sql.SQLException: Closed Connection
	// // 江西的问题已经找到原因，因为出了ORA-00600，导致连接池的连接关闭。在这里判断不出来。
	// // 避免办法配置 oracle-ds.xml check-valid-connection-sql 项
	// protected Connection confirmOpen(Connection conn) throws SQLException {
	//
	// for (int i = 1; conn.isClosed() && i <= 100; i++) {
	// logger.error("该连接是一个关闭的连接，重新再取一次" + i + ":" + conn);
	// conn = newConnection();
	// }
	//
	// return conn;
	// }
	// // UPD End

	/**
	 * 从DataSource中取一个数据库联接，需要自行关闭
	 * 
	 * @throws SQLException
	 */
	public Connection newConnection() throws SQLException {
		Connection conn = null;
		if (jdbcDriver != null) {
			try {
				conn = DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPass);
				logger.debug("---直接创建JDBC数据库连接对象。" + conn);
			} catch (Exception exp) {
				logger.error(exp.getMessage(), exp);
			}
		} else {
			conn = ds.getConnection();
			logger.debug("---从数据源中取得数据库连接对象。" + conn);
		}

		return conn;
	}

	/**
	 * 当没有事务时关闭数据库连接
	 * 
	 * @throws SQLException if a database access error occurs
	 */
	public void closeConnection() throws SQLException {
		logger.debug(">>>closeConnection()");
		if (!transactionStarted) {
			try {
				DbUtils.close(dbConn);
				logger.debug(" ---释放并关闭数据库连接对象。" + dbConn);
			} catch (SQLException e) {
				logger.error(" ---关闭数据库连接时发生错误。" + dbConn, e);
				throw e;
			} finally {
				dbConn = null;
			}
		}
		logger.debug("<<<closeConnection()");
	}

	/**
	 * 启动事务模式
	 * 
	 * @throws SQLException if a database access error occurs
	 */
	public void startTransaction() throws SQLException {
		startTransaction(Connection.TRANSACTION_READ_COMMITTED);
	}

	/**
	 * 启动事务模式
	 * @param transactionIsolation 事务隔离级别，
	 * 以下 Connection 常量之一：Connection.TRANSACTION_READ_UNCOMMITTED、
	 *							 Connection.TRANSACTION_READ_COMMITTED、
	 *							 Connection.TRANSACTION_REPEATABLE_READ 或 Connection.TRANSACTION_SERIALIZABLE。
	 * （注意，不能使用 Connection.TRANSACTION_NONE，因为它指定了不受支持的事务。） 
	 * @throws SQLException if a database access error occurs
	 */
	public void startTransaction(int transactionIsolation) throws SQLException {
		logger.debug(">>>startTransaction(transactionIsolation: " + transactionIsolation + ")");

		Connection conn = getConnection();
		conn.setAutoCommit(false);
		conn.setTransactionIsolation(transactionIsolation);
		transactionStarted = true;

		logger.debug("<<<startTransaction(transactionIsolation: " + transactionIsolation + ")");
	}

	/**
	 * 回滚事务
	 * @throws SQLException if a database access error occurs or this
     *            <code>Connection</code> object is in auto-commit mode
	 */
	public void rollbackTransaction() throws SQLException {
		logger.debug(">>>rollbackTransaction()");
		dbConn.rollback();
		logger.debug("<<<rollbackTransaction()");
	}
	
	/**
	 * 提交事务
	 * @throws SQLException if a database access error occurs or this
     *            <code>Connection</code> object is in auto-commit mode
	 */
	public void commitTransaction() throws SQLException {
		logger.debug(">>>commitTransaction()");
		dbConn.commit();
		logger.debug("<<<commitTransaction()");
	}
	
	/**
	 * 回滚事务到保存点
	 * @throws SQLException if a database access error occurs or this
     *            <code>Connection</code> object is in auto-commit mode
	 */
	public void rollbackTransaction(Savepoint point) throws SQLException {
		logger.debug(">>>rollbackTransaction()");
		dbConn.rollback(point);
		logger.debug("<<<rollbackTransaction()");
	}

	/**
	 * 结束事务
	 * 
	 * @throws SQLException if a database access error occurs
	 */
	public void endTransaction() throws SQLException {
		logger.debug(">>>endTransaction()");

		transactionStarted = false;
		closeConnection();

		logger.debug("<<<endTransaction()");
	}

	/**
	 * 为当前事务状态设置一个匿名保存点
	 * @throws SQLException if a database access error occurs or this
     *            <code>Connection</code> object is in auto-commit mode
	 */
	public Savepoint setTransactionSavePoint() throws SQLException {
		logger.debug(">>>setTransactionSavePoint()");
		Savepoint point = dbConn.setSavepoint();
		logger.debug("<<<setTransactionSavePoint()");
		return point;
	}

	/**
	 * 为当前事务状态设置一个有名字保存点
	 * @throws SQLException if a database access error occurs or this
     *            <code>Connection</code> object is in auto-commit mode
	 */
	public Savepoint setTransactionSavePoint(String name) throws SQLException {
		logger.debug(">>>setTransactionSavePoint(" + name + ")");
		Savepoint point = dbConn.setSavepoint(name);
		dbConn.setSavepoint();
		logger.debug("<<<setTransactionSavePoint(" + name + ")");
		return point;
	}
	
	/**
	 * 释放事务保存点
	 * @throws SQLException if a database access error occurs or
     *            the given <code>Savepoint</code> object is not a valid 
     *            savepoint in the current transaction
	 */
	public Savepoint releaseTransactionSavePoint(Savepoint point) throws SQLException {
		logger.debug(">>>releaseTransactionSavePoint(" + point + ")");
		dbConn.releaseSavepoint(point);
		logger.debug("<<<releaseTransactionSavePoint(" + point + ")");
		return point;
	}
}
